home *** CD-ROM | disk | FTP | other *** search
- #include <Events.h>
- #include <Resources.h>
- #include <Memory.h>
- #include <ToolUtils.h>
- #include <Menus.h>
- #include <LowMem.h>
- #include <Traps.h>
-
- #define CurMenuID (*(short *)0xB54)
- #define CurMenuItem (*(short *)0xB56)
-
- // Need to patch: MenuSelect, WaitMouseUp,
-
- #ifndef powerc
- #ifdef THINK_C
- #pragma parameter __D0 SetA4(__D0)
- pascal long SetA4(long newA4) = 0xC18C;
-
- #define SetCurrentA4() SetA4((long)&main)
- #else
- #include <A4Stuff.h>
- // #include <SetUpA4.h>
- #endif
- #else
- #define SetCurrentA4() 0
- #define SetA4(x) 0
-
- ProcInfoType __procinfo = kCStackBased
- | RESULT_SIZE(kFourByteCode)
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(void *)));
- #endif
-
- pascal long (*gOldMenuSelect)(Point pt);
- pascal void (*gOldHiliteMenu)(short);
- pascal void (*gOldDrawMenuBar)(void);
- pascal void (*gOldJShieldCursor)(short left, short top, short right, short bottom);
-
- pascal long myMenuSelect(Point pt);
- pascal void myHiliteMenu(short);
- pascal void myDrawMenuBar(void);
- pascal void myJShieldCursor(short left, short top, short right, short bottom);
-
- enum {
- uppMenuSelectProcInfo = kPascalStackBased | RESULT_SIZE(kFourByteCode) | STACK_ROUTINE_PARAMETER(1, kFourByteCode)
- };
-
-
- pascal short (*gOldWaitMouseUp)(void);
-
- pascal short myWaitMouseUp(void);
-
- enum {
- uppWaitMouseUpProcInfo = kPascalStackBased | RESULT_SIZE(kTwoByteCode)
- };
-
- // Globals
-
- static void GNEFilterGlue(void);
- static void myMenuSelectLoopCode(void);
-
-
- static GNEFilterUPP gFilterProc;
-
- static Ptr gGNEStack;
- static long gGNEPC;
- static GrafPtr gGNEPort;
- static Ptr gMenuSelectStack;
- static long gMenuSelectPC;
- static GrafPtr gMenuSelectPort;
-
- static Point gMSPoint;
- static int gDoSelect = false;
-
- static short gHaveFakeMSResult = false;
- static long gFakeMSResult;
-
- static short gGNEReEntrancy;
- static short gInMenuSelect = false;
-
- static Handle gMacsBug;
-
- enum {
- kStackSize = 1024*24
- };
-
- void main(void)
- {
- long oldA4;
- THz oldZone;
-
- // Set up A4, so we can access our globals.
- oldA4 = SetCurrentA4();
-
- // Set the current zone to the system zone. In the 680x0 case, this
- // is not necessary, but it's not a bad idea and it keeps us out of
- // trouble when traps that we don't expect to have side effects
- // unexpectedlty allocate memory from the current zone. One example
- // of this is the NewRoutineDescriptor routine.
- oldZone = GetZone();
- SetZone(SystemZone());
-
- // We need to detach our code, so that we stay around.
- DetachResource(GetResource('INIT', 237));
- DetachResource(gMacsBug = Get1Resource('PICT', 237));
-
- // Allocate the stack
-
- gMenuSelectStack = NewPtr(kStackSize) + kStackSize;
- gMenuSelectPC = (long) &myMenuSelectLoopCode;
-
- // Remember the old definition of GNEFilter
-
- gFilterProc = LMGetGNEFilter();
- LMSetGNEFilter((GNEFilterUPP)GNEFilterGlue);
-
- #if 1
-
- // Remember the old implementation of WaitMouseUp and MenuSelect.
- // gOldWaitMouseUp = (void *) GetToolTrapAddress(0xA977);
- gOldMenuSelect = (void *) GetToolTrapAddress(0xA93D);
-
- // Patch ourselves in.
- // SetToolTrapAddress(NewRoutineDescriptor((ProcPtr) &myWaitMouseUp,uppWaitMouseUpProcInfo,kPowerPCISA), 0xA977);
- SetToolTrapAddress(NewRoutineDescriptor((ProcPtr) &myMenuSelect, uppMenuSelectProcInfo,kPowerPCISA), 0xA93D);
-
- gOldHiliteMenu = (void*) GetToolTrapAddress(_HiliteMenu);
- SetToolTrapAddress((ProcPtr) &myHiliteMenu, _HiliteMenu);
-
- gOldDrawMenuBar = (void*) GetToolTrapAddress(_DrawMenuBar);
- SetToolTrapAddress((ProcPtr)&myDrawMenuBar, _DrawMenuBar);
-
- // Path shieldcursor to pick up updates.
-
- gOldJShieldCursor = *(QDJShieldCursorProcPtr*)0x0808;
- *(QDJShieldCursorProcPtr*)0x0808 = myJShieldCursor;
-
- #endif
- // Restore the old zone again
- SetZone(oldZone);
-
- // And restore the value of A4 on the way out.
- SetA4(oldA4);
- }
-
- static void DoMacsBugThing(EventRecord *erp) {
- char ASCIIval = (char) erp->message;
- Rect r, ir;
- WindowPtr wp;
- WindowRecord wr;
- EventRecord xer;
- Rect gray = GetMainDevice()[0]->gdPMap[0][0].bounds;
- GrafPtr oldPort;
-
- long oldA4 = SetCurrentA4();
-
- if (gInMenuSelect) {
- GetPort(&oldPort);
- if (ASCIIval == 'Q' || ASCIIval == 'q') {
- if (erp->modifiers & cmdKey) {
- r.top = (gray.bottom - gray.top - 400) / 2;
- r.left = (gray.right - gray.left - 640) / 2;
- r.bottom = r.top + 400;
- r.right = r.left + 640;
- InsetRect(&r, 1, 1);
- wp = NewWindow(&wr, &r, "\p", false, plainDBox, (WindowRef) -1, false, 237);
- SetPort(wp);
- SetWindowPic(wp, (PicHandle) gMacsBug);
- ShowHide(wp, true);
- DrawPicture((PicHandle) gMacsBug, &wp->portRect);
- for (;;) {
- GetNextEvent(keyDownMask, &xer);
- SetPort(wp);
- ir.left = 77;
- ir.right = 78;
- ir.top = 387;
- ir.bottom = 396;
- StdRect(kQDGrafVerbInvert, &ir);
- if (!gInMenuSelect) break;
- // if (xer.what == keyDown && '\r' == (char) xer.message) break;
- }
- SetWindowPic(wp, (PicHandle) 0);
- CloseWindow(wp);
- }
- }
- SetPort(oldPort);
- }
-
- SetA4(oldA4);
- }
-
- asm void GNEFilterGlue(void)
- {
- machine 68020
- CLR.L -(A7)
- MOVEM.L D0-D7/A0-A6,-(A7)
- JSR SetCurrentA4
- MOVE.L gFilterProc,60(A7)
- TST.W gGNEReEntrancy
- BNE @ReEntrancyDetected
- TST.W (A1)
- BNE.S @RealEvent
- ST.B gGNEReEntrancy
- BSR.S @DispatchToMenuSelectingThread
- @ReturnFromMenuSelect:
- CLR.W gGNEReEntrancy
- TST.W gHaveFakeMSResult
- MOVE.L gGNEPort,A6
- BEQ.S @Return
- MOVEM.L (A7)+,D0-D7/A0-A3
- MOVE.W #mouseDown,0(A1) // EventRecord.what(A1)
- MOVE.L #0x00020037,10(A1) // EventRecord.where(A1)
- MOVE.W #0x0101,D0
- MOVEM.L (A7)+,A4-A5
- MOVE.W D0,12(A7)
- BRA.S @RestoreGNEPort
-
- @DispatchToMenuSelectingThread:
- MOVE.L (A7)+,gGNEPC
- MOVE.L A7,gGNEStack
- MOVE.L (A5),A0
- MOVE.L (A0),gGNEPort
- MOVE.L 0x110,0xF0
- CLR.L 0x110
- MOVE.L gMenuSelectStack,A7
- MOVE.L gMenuSelectPC,-(A7)
- RTS
-
- @RealEvent:
- CMP.W #mouseDown,0(A1) // EventRecord.what(A1)
- BNE @Exit
- TST.W gInMenuSelect
- BEQ @Exit
- ST.B gGNEReEntrancy
- @Lock:
- BSR.S @DispatchToMenuSelectingThread
-
- TST.W gInMenuSelect
- BEQ.S @ReturnFromMenuSelect
- BRA.S @Lock
-
- @Return:
- MOVEM.L (A7)+,D0-D7/A0-A5
- @RestoreGNEPort:
- MOVE.L A0,-(A7)
- MOVE.L (A5),A0
- MOVE.L A6,(A0)
- MOVE.L (A7)+,A0
- MOVE.L (A7)+,A6
- RTS
-
- @Exit:
- @ReEntrancyDetected:
- MOVEM.L (A7)+,D0-D7/A0-A6
- CMP.W #keyDown,0(A1)
- BNE.S @notMacsBug
- MOVEM.L A0-A3/D0-D3,-(A7)
- LINK A6,#0
- MOVE.L A1,-(A7)
- JSR DoMacsBugThing
- UNLK A6
- MOVEM.L (A7)+,A0-A3/D0-D3
- @notMacsBug:
- RTS
- }
-
- static asm void YieldToTheAppAndHopeItDoesntCallMenuSelectAgain(void)
- {
- MOVEM.L D0-D7/A0-A6,-(A7)
- MOVE.L A7,gMenuSelectStack
- MOVE.L 0xF0,0x110
- PEA @Return
- MOVE.L (A7)+,gMenuSelectPC
- MOVE.L (A5),A0
- MOVE.L (A0),gMenuSelectPort
- MOVE.L gGNEStack,A7
- MOVE.L gGNEPC,-(A7)
- RTS
-
- @Return:
- MOVEM.L (A7)+,D0-D7/A0-A6
- MOVE.L A0,-(A7)
- MOVE.L (A5),A0
- MOVE.L gMenuSelectPort,(A0)
- MOVE.L (A7)+,A0
- RTS
- }
-
- static void ShowHideScreen(Boolean show)
- {
- static Ptr sRealBase;
- PixMapHandle devicePixMap;
-
- devicePixMap = (*GetMainDevice())->gdPMap;
-
- if (!show)
- {
- sRealBase = (*devicePixMap)->baseAddr;
- (*devicePixMap)->baseAddr = LMGetROMBase() + 1024;
- }
- else
- {
- (*devicePixMap)->baseAddr = sRealBase;
- }
- }
-
- static Rect sLastWinRect = { 0 };
- static RgnHandle sLastGrayRgn = NULL;
- static int sDoPaint = false;
-
- static UniversalProcPtr gOldEraseRectAddress;
- static UniversalProcPtr gOldEraseRgnAddress;
-
- static void RestoreGrayRgn(RgnHandle clipRgn)
- {
- WindowPtr blastWindow;
- Rect winRect = sLastWinRect;
- RgnHandle clobberedRgn;
- GrafPtr currentPort;
-
- winRect.bottom += 2;
- winRect.right += 2;
- winRect.left -= 1;
-
- // Pad the rect out so it covers alignment for menu saving
-
- InsetRect(&winRect, -3, -3);
-
- CopyRgn(sLastGrayRgn, GetGrayRgn());
- DisposeRgn(sLastGrayRgn);
- sLastGrayRgn = NULL;
-
- clobberedRgn = NewRgn();
- RectRgn(clobberedRgn, &winRect);
-
- // Restore the window regions
- CalcVisBehind(FrontWindow(), clobberedRgn);
-
- // Carve out any new clip
-
- if (clipRgn)
- {
- sLastGrayRgn = NewRgn();
- CopyRgn(GetGrayRgn(), sLastGrayRgn);
-
- DiffRgn(GetGrayRgn(), clipRgn, GetGrayRgn());
- CalcVisBehind(FrontWindow(), clipRgn);
- }
-
- if (sDoPaint)
- {
- if (clipRgn)
- {
- Rect clipRect = (*clipRgn)->rgnBBox;
-
- if (SectRect(&clipRect, &winRect, &clipRect))
- sDoPaint = false;
- }
- else
- {
- sDoPaint = false;
- }
-
- GetPort(¤tPort);
- PaintBehind(FrontWindow(), clobberedRgn);
- SetPort(currentPort);
- }
-
- CalcVisBehind(FrontWindow(), clobberedRgn);
-
- // ShowHideScreen(false);
-
- // Generate the update and clear the hole
-
- #if 0
- blastWindow = NewCWindow(NULL, &winRect, "\p", false, altDBoxProc, (WindowPtr)-1, false, 0);
- ShowHide(blastWindow, true);
- DisposeWindow(blastWindow);
- #endif
-
- // ShowHideScreen(true);
- }
-
- static void BlastAndYield(void)
- {
- static sLastBlast = 0;
-
- CGrafPtr winPort;
- Rect winRect;
- Rect grayRect;
- Rect tempRect;
- RgnHandle menuRgn = NULL;
- WindowPtr blastWindow;
- Boolean doUpdate;
-
- long time = TickCount();
-
- if (time < sLastBlast + 10)
- return;
-
- sLastBlast = time;
-
- GetCWMgrPort(&winPort);
-
- winRect = (*winPort->clipRgn)->rgnBBox;
- grayRect = (*GetGrayRgn())->rgnBBox;
-
- SectRect(&winRect, &grayRect, &tempRect);
-
- doUpdate = !EmptyRect(&winRect) && !EqualRect(&winRect, &sLastWinRect) && !EqualRect(&grayRect, &tempRect);
-
- if (doUpdate)
- {
- Rect tempLast = winRect;
-
- winRect.bottom += 2;
- winRect.right += 2;
- winRect.left -= 1;
-
- menuRgn = NewRgn();
- RectRgn(menuRgn, &winRect);
-
- if (sLastGrayRgn)
- {
- RestoreGrayRgn(menuRgn);
- }
- else
- {
- sLastGrayRgn = NewRgn();
- CopyRgn(GetGrayRgn(), sLastGrayRgn);
-
- DiffRgn(GetGrayRgn(), menuRgn, GetGrayRgn());
- CalcVisBehind(FrontWindow(), menuRgn);
- }
-
- DisposeRgn(menuRgn);
-
- sLastWinRect = tempLast;
-
- #if 0
- sLastWinRect = winRect;
-
- winRect.bottom += 2;
- winRect.right += 2;
- winRect.left -= 1;
-
- sLastGrayRgn = NewRgn();
- CopyRgn(GetGrayRgn(), sLastGrayRgn);
-
- menuRgn = NewRgn();
- RectRgn(menuRgn, &winRect);
-
- DiffRgn(GetGrayRgn(), menuRgn, GetGrayRgn());
-
- #if 0
-
- ShowHideScreen(false);
-
- // We blast the gray rgn for minimal possible bug generate an update for the area
- // restored by the menu manager.
-
- blastWindow = NewCWindow(NULL, &winRect, "\p", false, altDBoxProc, (WindowPtr)-1, false, 0);
- ShowHide(blastWindow, true);
- DisposeWindow(blastWindow);
-
- ShowHideScreen(true);
- #endif
-
- CalcVisBehind(FrontWindow(), menuRgn);
- DisposeRgn(menuRgn);
- #endif
- }
-
- YieldToTheAppAndHopeItDoesntCallMenuSelectAgain();
- }
-
- RGBColor white = {-1, -1, -1};
-
- pascal short myWaitMouseUp(void)
- {
- // Set up A4, so we can access our globals.
- long oldA4;
- short result;
- long temp;
- short menuID, menuItem;
- short menuModifiers;
- MenuHandle mh;
- EventRecord keyEvent;
- UniversalProcPtr patchedEraseRectAddress;
- UniversalProcPtr patchedEraseRgnAddress;
- RGBColor oldBack;
-
- oldA4 = SetCurrentA4();
-
- patchedEraseRectAddress = GetToolTrapAddress(0xA8A3);
- patchedEraseRgnAddress = GetToolTrapAddress(0xA8D4);
- SetToolTrapAddress(gOldEraseRectAddress, 0xA8A3);
- SetToolTrapAddress(gOldEraseRgnAddress, 0xA8D4);
- GetBackColor(&oldBack);
- RGBBackColor(&white);
- BlastAndYield();
- RGBBackColor(&oldBack);
- SetToolTrapAddress(patchedEraseRectAddress, 0xA8A3);
- SetToolTrapAddress(patchedEraseRgnAddress, 0xA8D4);
-
- // Call the old WaitMouseUp:
- #ifndef powerc
- result = gOldWaitMouseUp();
- #else
- result = CallUniversalProc((UniversalProcPtr)gOldWaitMouseUp, uppWaitMouseUpProcInfo);
- #endif
-
- // And restore the value of A4 on the way out.
- SetA4(oldA4);
-
- return result;
- }
-
- #if 0
-
- static Rect gLastMenuRect = {0, 0, 0, 0};
- static void* gOldMBarHook;
-
- static asm void myMBarHook(void)
- {
- MOVEM.L A4,-(SP)
- JSR SetCurrentA4
- MOVE.L 8(SP),A0
- MOVE.L (A0)+,gLastMenuRect.top
- MOVE.L (A0),gLastMenuRect.bottom
- TST.L gOldMBarHook
- MOVEQ #0,D0
- BEQ @Exit
- MOVE.L gOldMBarHook,A0
- MOVEM.L (SP)+,A4
- JMP (A0)
-
- @Exit
- MOVEM.L (SP)+,A4
- RTD #4
- }
-
- #endif
-
- pascal void myDrawMenuBar(void)
- {
- long oldA4 = SetCurrentA4();
-
- if (!gInMenuSelect)
- gOldDrawMenuBar();
-
- SetA4(oldA4);
- }
-
- pascal void myHiliteMenu(short menuID)
- {
- long oldA4 = SetCurrentA4();
-
- if (!gInMenuSelect)
- gOldHiliteMenu(menuID);
-
- SetA4(oldA4);
- }
-
- pascal void myJShieldCursor(short left, short top, short right, short bottom)
- {
- long oldA4 = SetCurrentA4();
- Rect shieldRect;
- Rect bigLastRect;
-
- SetRect(&shieldRect, left, top, right, bottom);
- bigLastRect = sLastWinRect;
- InsetRect(&bigLastRect, -2, -2);
-
- if (gInMenuSelect && !gGNEReEntrancy && sLastGrayRgn && SectRect(&shieldRect, &bigLastRect, &shieldRect))
- sDoPaint = true;
-
- gOldJShieldCursor(left, top, right, bottom);
-
- SetA4(oldA4);
- }
-
- void myMenuSelectLoopCode(void)
- {
- while (true)
- {
- if (gDoSelect)
- {
-
- gDoSelect = false;
-
- gOldWaitMouseUp = (void *) GetToolTrapAddress(0xA977);
- SetToolTrapAddress(NewRoutineDescriptor((ProcPtr) &myWaitMouseUp,uppWaitMouseUpProcInfo,kPowerPCISA), 0xA977);
-
- #if 0
- gOldMBarHook = (void*)LMGetMBarHook();
- LMSetMBarHook(myMBarHook);
-
- gLast
- #endif
-
- SetRect(&sLastWinRect, 0, 0, 0, 0);
-
- gInMenuSelect = true;
- gOldEraseRectAddress = GetToolTrapAddress(0xA8A3);
- gOldEraseRgnAddress = GetToolTrapAddress(0xA8D4);
- gFakeMSResult = gOldMenuSelect(gMSPoint);
- gInMenuSelect = false;
-
- if (sLastGrayRgn)
- RestoreGrayRgn(0);
-
- //LMSetMBarHook(gOldMBarHook);
- SetToolTrapAddress((ProcPtr) gOldWaitMouseUp, 0xA977);
-
- if ((gFakeMSResult & 0xFFFF0000) && (gFakeMSResult & 0xFFFF))
- gHaveFakeMSResult = true;
- else
- gHaveFakeMSResult = false;
- }
- YieldToTheAppAndHopeItDoesntCallMenuSelectAgain();
- }
- }
-
- pascal long myMenuSelect(Point pt)
- {
- // Set up A4, so we can access our globals.
- long oldA4;
- long result;
- int oldState;
-
- oldA4 = SetCurrentA4();
-
- if (gHaveFakeMSResult)
- {
- gHaveFakeMSResult = false;
- result = gFakeMSResult;
- }
- else if (StillDown())
- {
- gDoSelect = true;
- gMSPoint = pt;
- result = false;
- }
- else
- {
- // Call the old MenuSelect:
- #ifndef powerc
- result = gOldMenuSelect(pt);
- #else
- result = CallUniversalProc((UniversalProcPtr)gOldMenuSelect, uppMenuSelectProcInfo, pt);
- #endif
- }
-
-
- // And restore the value of A4 on the way out.
- SetA4(oldA4);
-
- return result;
- }
-